# @Author : Fioman
# @Phone : 13149920693
"""
三拼板最新算法: 主要改动就是无中缝的板子,采用分隔方式去搞.如果实在一点中缝没有,那个就只能标注了.
"""
import os
import time

import cv2

from db_tools.db_handler import DbHandler
from tools.fioman_math_tools import pix_pos_to_robot, get_two_line_angle
from vision_process.image_process_new import get_width_height_by_image_name_2p, check_total_board_is_ok
from vision_process.image_process_common import *

db = DbHandler()
cp = ConfigParams()
jointLineExtend = 5
upBoxSlice = 0.4
middleBoxSlice = (0.3, 0.7)
downBoxSlice = 0.6

tryBeginIndex = 1
calcArgs3pin = {
    "1": [[2], 17, 15, 8, 15, [15, 20, 30, 45, 55], 0.2],
    "2": [[2], 17, 15, 8, 15, [10, 20, 30, 50, 60], 0],
}


def image_show(name, image, showState=False):
    """
    显示图片,调试的时候显示图像,按照一定的比例进行缩放
    :param name: 显示的图片的窗口的名称
    :param image: 显示的图片
    :param showState: 是否显示的状态
    :return:
    """
    if showState:
        sizeScale = 4.5
        newWidth = int(image.shape[1] / sizeScale)
        newHeight = int(image.shape[0] / sizeScale)
        showImage = cv.resize(image, (newWidth, newHeight), cv.INTER_AREA)
        cv.namedWindow("{}".format(name))
        cv.imshow("{}".format(name), showImage)
        cv.waitKey(0)


def find_middle_line_with_two_mid(board, lineOffset, edgeLineAngle, splitNumber):
    """
    带有两个中缝的查找中缝的方法,这里有两种情况,一种是只找一个中缝,一个是找两个中缝.
    假如只找一个中缝的话,看是找上面还是找下面,这个我感觉就是找两个中缝就可以了.
    @param board:
    @param lineOffset:
    @param edgeLineAngle:
    @param splitNumber:
    @return:
    """
    offset = board.shape[1] // splitNumber
    findLineKb1 = []
    findLineKb2 = []
    lineKRes1 = None
    lineKRes2 = None
    edgeLineAngle1, edgeLineAngle2 = edgeLineAngle
    for i in range(splitNumber):
        boardUsed = board[:, offset * i:offset * (i + 1)]
        image_show(f"boardUsed_{i + 1}", boardUsed)
        cnts = cv.findContours(boardUsed.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
        cnts = imutils.grab_contours(cnts)
        cntsSorted = sorted(cnts, key=cv.contourArea, reverse=True)
        if len(cntsSorted) == 0:
            continue
        _, (w, h), _ = cv.minAreaRect(cntsSorted[0])
        rectBox = cv.minAreaRect(cntsSorted[0])
        rectBoxPoints = np.int0(cv.boxPoints(rectBox))
        leftTop, rightTop, rightBottom, leftBottom = get_rect_points_clockwise(rectBoxPoints)
        midEdgeOffset1 = get_two_points_middle(leftTop, rightTop)[1]
        midEdgeOffset2 = board.shape[0] - get_two_points_middle(leftBottom, rightBottom)[1]
        if midEdgeOffset1 < 10 * cp.mm2pix and midEdgeOffset2 < 10 * cp.mm2pix:
            continue
        if midEdgeOffset1 >= 10 * cp.mm2pix:
            findLineKb1.append(get_line_k_and_b(leftTop, rightTop))
        if midEdgeOffset2 > 10 * cp.mm2pix:
            findLineKb2.append(get_line_k_and_b(leftBottom, rightBottom))
        useImae = cv.cvtColor(boardUsed, cv.COLOR_GRAY2BGR)
        cv.drawContours(useImae, [rectBoxPoints], -1, colorGreen, 2)
        image_show(f"MiddleLineFinded_{i + 1}", useImae)

    if len(findLineKb1) > 0:
        cv.destroyAllWindows()
        lineKRes = sorted(findLineKb1, key=lambda x: abs(edgeLineAngle1 - get_angle_by_k(x[0])))
        lineKRes1 = lineKRes[0]

    if len(findLineKb2) > 0:
        cv.destroyAllWindows()
        lineKRes = sorted(findLineKb2, key=lambda x: abs(edgeLineAngle2 - get_angle_by_k(x[0])))
        lineKRes2 = lineKRes[0]
    if lineKRes1 is not None and lineKRes2 is not None:
        return [lineKRes1, lineKRes2]
    else:
        return None


def find_middle_line(board, boardPos, edgeLineAngle, splitNumber):
    """
    如果中缝找不到了,通过将图像分段,然后就是分段时候,要和之前的斜率做对比,斜率差值最小的就是,这个是针对
    有中缝,如果本身的boardPos = "middle"的时候,这个时候,斜率可能都不存在,先不管这种情况
    @param board:
    @param boardPos:
    @param edgeLineAngle:
    @param splitNumber:
    @return:
    """
    offset = board.shape[1] // splitNumber
    findLineKb = []
    for i in range(splitNumber):
        boardUsed = board[:, offset * i:offset * (i + 1)]
        image_show(f"boardUsed_{i + 1}", boardUsed)
        cnts = cv.findContours(boardUsed.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
        cnts = imutils.grab_contours(cnts)
        cntsSorted = sorted(cnts, key=cv.contourArea, reverse=True)
        if len(cntsSorted) == 0:
            continue
        _, (w, h), _ = cv.minAreaRect(cntsSorted[0])
        rectBox = cv.minAreaRect(cntsSorted[0])
        rectBoxPoints = np.int0(cv.boxPoints(rectBox))
        leftTop, rightTop, rightBottom, leftBottom = get_rect_points_clockwise(rectBoxPoints)
        midEdgeOffset = 0
        if boardPos == "up":
            midEdgeOffset = board.shape[0] - get_two_points_middle(leftBottom, rightBottom)[1]
        elif boardPos == "down":
            midEdgeOffset = get_two_points_middle(leftTop, rightTop)[1]
        if midEdgeOffset < 10 * cp.mm2pix:
            continue
        useImae = cv.cvtColor(boardUsed, cv.COLOR_GRAY2BGR)
        cv.drawContours(useImae, [rectBoxPoints], -1, colorGreen, 2)
        image_show(f"MiddleLineFinded_{i + 1}", useImae)
        if boardPos == "up":
            findLineKb.append(get_line_k_and_b(leftBottom, rightBottom))
        elif boardPos == "down":
            findLineKb.append(get_line_k_and_b(leftTop, rightTop))
    if len(findLineKb) > 0:
        cv.destroyAllWindows()
        lineKRes = sorted(findLineKb, key=lambda x: abs(edgeLineAngle - get_angle_by_k(x[0])))
        return lineKRes[0]
    else:
        return None


def check_inner_board_3p(board, width, height, calcThresBig, calcThresSmall,
                         boardColor, boardPos, upBox, downBox, totalBoard):
    totalHeightPix, totalWidthPix = board.shape[:2]
    totalWidthMm, totalHeightMm = round(
        totalWidthPix / cp.mm2pix, 2), round(totalHeightPix / cp.mm2pix, 2)
    moveWidth = int(totalWidthPix * 0.15)
    moveHeight = int(totalHeightPix * 0.25)
    res = {
        "result": "error",
        "box": None,
        "info": "",
        "calcSize": (totalWidthMm, totalHeightMm),
        "calcError": (0, 0)
    }
    widthMax = width / cp.mm2pix + calcThresBig
    heightMax = height / cp.mm2pix + calcThresBig
    widthMin = width / cp.mm2pix - calcThresSmall
    heightMin = height / cp.mm2pix - calcThresSmall
    widthMm = round(width / cp.mm2pix, 2)
    heightMm = round(height / cp.mm2pix, 2)
    moveAngleUsed = board.copy()
    try:
        cv.rectangle(moveAngleUsed, (0, 0), (moveWidth, moveHeight), 0, -1)
        cv.rectangle(moveAngleUsed, (moveAngleUsed.shape[1], 0),
                     (moveAngleUsed.shape[1] - moveWidth, moveHeight), 0, -1)
        cv.rectangle(moveAngleUsed, (0, moveAngleUsed.shape[0] - moveHeight),
                     (moveWidth, moveAngleUsed.shape[0]), 0, -1)
        cv.rectangle(moveAngleUsed,
                     (moveAngleUsed.shape[1] - moveWidth, moveAngleUsed.shape[0] - moveHeight),
                     (moveAngleUsed.shape[1], moveAngleUsed.shape[0]), 0, -1)
        image_show("AngleMoved", moveAngleUsed)
        cnts = cv.findContours(
            moveAngleUsed.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        cnts = imutils.grab_contours(cnts)
        cntsSorted = sorted(cnts, key=cv.contourArea, reverse=True)
        if len(cntsSorted) == 0:
            res["result"] = "error"
            res["info"] = f"{boardPos} 框,找内板失败,没有找到任何轮廓"
            return res
        rectBox = cv.minAreaRect(cntsSorted[0])
        rectBoxPoints = np.intp(cv.boxPoints(rectBox))
        leftTop, rightTop, rightBottom, leftBottom = get_rect_points_clockwise(rectBoxPoints)
        # 判断是否是没有中缝,如果是上框,就判断和底部的距离太小,就认为是没有中缝
        if boardPos == "up":
            edgeLineAngle = get_angle_by_k(get_line_k_and_b(leftTop, rightTop)[0])
            yOffset = (board.shape[0] - get_two_points_middle(leftBottom, rightBottom)[1]) // cp.mm2pix
            print(f"上框信息: 第一边角度: {edgeLineAngle:.2f},中缝底部偏移: {yOffset:.2f}")
        elif boardPos == "middle":
            edgeLineAngle1 = get_angle_by_k(get_line_k_and_b(upBox[0], upBox[1])[0])
            edgeLineAngle2 = get_angle_by_k(get_line_k_and_b(downBox[0], downBox[1])[0])
            edgeLineAngle = [edgeLineAngle1, edgeLineAngle2]
            yOffset1 = (get_two_points_middle(leftTop, rightTop)[1]) // cp.mm2pix
            yOffset2 = (board.shape[0] - get_two_points_middle(leftBottom, rightBottom)[1]) // cp.mm2pix
            yOffset = min(yOffset1, yOffset2)
            print(f"中框信息: 上框角度: {edgeLineAngle1:.2f},下框角度:{edgeLineAngle2:.2f} "
                  f"偏移上: {yOffset1:.2f},偏移下: {yOffset2:.2f}")
        else:
            edgeLineAngle = get_angle_by_k(get_line_k_and_b(leftTop, rightTop)[0])
            yOffset = (get_two_points_middle(leftTop, rightTop)[1]) // cp.mm2pix
            print(f"下框信息: 第三边角度: {edgeLineAngle:.2f},中缝底部偏移: {yOffset:.2f}")
        middleIsOk = True
        if abs(yOffset) < 10 and boardPos != "middle":
            middleIsOk = False
            middleLineKB = find_middle_line(board, boardPos, edgeLineAngle, splitNumber=4)
            if middleLineKB is None:
                middleLineKB = find_middle_line(board, boardPos, edgeLineAngle, splitNumber=6)
            if middleLineKB is None:
                middleLineKB = find_middle_line(board, boardPos, edgeLineAngle, splitNumber=8)
            if middleLineKB is not None:
                middleIsOk = True
                middleK, middleB = middleLineKB
                leftK, leftB = get_line_k_and_b(leftTop, leftBottom)
                rightK, rightB = get_line_k_and_b(rightTop, rightBottom)
                if boardPos == "up":
                    leftBottom = get_two_lines_intersection(leftK, leftB, middleK, middleB)
                    leftBottom = int(leftBottom[0]), int(leftBottom[1])
                    rightBottom = get_two_lines_intersection(rightK, rightB, middleK, middleB)
                    rightBottom = int(rightBottom[0]), int(rightBottom[1])
                else:
                    leftTop = get_two_lines_intersection(leftK, leftB, middleK, middleB)
                    leftTop = int(leftTop[0]), int(leftTop[1])
                    rightTop = get_two_lines_intersection(rightK, rightB, middleK, middleB)
                    rightTop = int(rightTop[0]), int(rightTop[1])

        if abs(yOffset) < 10 and boardPos == "middle":
            middleIsOk = False
            middleLineKB = find_middle_line_with_two_mid(
                board, [yOffset1, yOffset2], edgeLineAngle, splitNumber=4)
            if middleLineKB is None:
                middleLineKB = find_middle_line_with_two_mid(
                    board, [yOffset1, yOffset2], edgeLineAngle, splitNumber=6)
            if middleLineKB is None:
                middleLineKB = find_middle_line_with_two_mid(
                    board, [yOffset1, yOffset2], edgeLineAngle, splitNumber=8)
            if middleLineKB is not None:
                middleIsOk = True
                middleK1, middleB1 = middleLineKB[0]
                middleK2, middleB2 = middleLineKB[1]
                leftK, leftB = get_line_k_and_b(leftTop, leftBottom)
                rightK, rightB = get_line_k_and_b(rightTop, rightBottom)
                leftBottom = get_two_lines_intersection(leftK, leftB, middleK2, middleB2)
                leftBottom = int(leftBottom[0]), int(leftBottom[1])
                rightBottom = get_two_lines_intersection(rightK, rightB, middleK2, middleB2)
                rightBottom = int(rightBottom[0]), int(rightBottom[1])
                leftTop = get_two_lines_intersection(leftK, leftB, middleK1, middleB1)
                leftTop = int(leftTop[0]), int(leftTop[1])
                rightTop = get_two_lines_intersection(rightK, rightB, middleK1, middleB1)
                rightTop = int(rightTop[0]), int(rightTop[1])

        if not middleIsOk:
            res["result"] = "error"
            res["info"] = f"{boardPos}框 找内板失败,找到的中缝位置不对"
            return res

        useImage = boardColor.copy()
        cv2.drawContours(useImage, [np.array([leftTop, rightTop, rightBottom, leftBottom])],
                         -1, colorGreen, 3)
        image_show("InnerBoardFinded", useImage)
        res["box"] = [leftTop, rightTop, rightBottom, leftBottom]
        widthFinded = round(get_two_point_distance(leftTop, rightTop) / cp.mm2pix, 2)
        heightFinded = round(get_two_point_distance(leftTop, leftBottom) / cp.mm2pix, 2)
        res["calcSize"] = (widthFinded, heightFinded)
        res["calcError"] = (round(widthFinded - widthMm, 2), round(heightFinded - heightMm, 2))
        if widthFinded < widthMin:
            res["result"] = "small"
            res["info"] = (f"{boardPos} 框,识别的宽度过小,识别的宽度为{widthFinded},"
                           f"工单确认的内板宽度为:{widthMm},误差{res['calcError'][0]}")
            return res
        if widthFinded > widthMax:
            res["result"] = "big"
            res["info"] = (f"{boardPos} 框,识别的宽度过大,识别的宽度为{widthFinded},"
                           f"工单确认的内板宽度为:{widthMm},误差{res['calcError'][0]}")
            return res

        if heightFinded < heightMin:
            res["result"] = "small"
            res["info"] = (f"{boardPos} 框,识别的高度过小,识别的高度为{heightFinded},"
                           f"工单确认的内板高度为:{heightMm},误差{res['calcError'][1]}")
            return res
        if heightFinded > heightMax:
            res["result"] = "big"
            res["info"] = (f"{boardPos} 框,识别的高度过大,识别的高度为{heightFinded},"
                           f"工单确认的内板高度为:{heightMm},误差{res['calcError'][1]}")
            return res
        boxFinded = res["box"]
        if boardPos == "middle":
            middleBoxPoints = [(p[0], p[1] + int(totalBoard.shape[0] * middleBoxSlice[0]))
                               for p in boxFinded]
            isOverLap1 = check_two_box_is_overlap(upBox, middleBoxPoints)
            isOverLap2 = check_two_box_is_overlap(middleBoxPoints, downBox)
            if isOverLap1 or isOverLap2:
                totalBoardColor = cv.cvtColor(totalBoard, cv.COLOR_GRAY2BGR)
                cv.drawContours(totalBoardColor,
                                [np.array(upBox), np.array([middleBoxPoints]), np.array(downBox)],
                                -1, colorGreen, 3)
                image_show("BoardOverLap", totalBoardColor)
                res["result"] = "error"
                res["info"] = "上下框出现叠板,识别失败~"
                return res
        res["result"] = "ok"
        res["info"] = "识别成功!"
        return res
    except Exception as e:
        errorInfo = f"程序出错: in check_inner_board_3p()  error: {str(e)}"
        print(errorInfo)
        res["result"] = "error"
        res["info"] = errorInfo
        return res


def get_inner_board_info_3p(board, upJointline, width, height, calcThresBig, calcThresSmall,
                            boardPos, isFirstBoard, isSizeCheck, upBox, downBox, totalBoard):
    boardColor = cv.cvtColor(board, cv.COLOR_GRAY2BGR)
    sizeDifRes = []
    sizeOkRes = []
    calcArgs = calcArgs3pin
    for tryTimes in range(tryBeginIndex, len(calcArgs.keys()) + 1):
        cv.destroyAllWindows()
        gaussianR, squareR, dilateKernel, closeTimes, openTimes, thresOffsetList, scharrRate = (
            calcArgs.get(str(tryTimes)))
        print("第{}次计算,计算参数:高斯半径:{},方差核:{},膨胀腐蚀核:{},闭操作次数:{},开操作次数:{},"
              "阈值offset:{},scharr比例:{}".format(
            tryTimes, gaussianR, squareR, dilateKernel, closeTimes,
            openTimes, thresOffsetList, scharrRate))
        if len(gaussianR) == 1:
            if gaussianR[0] == 0:
                blurred = board.copy()
            else:
                blurred = cv.GaussianBlur(board, (0, 0), gaussianR[0])
        else:
            d, colorSigma = gaussianR
            spaceSigma = int(d / 2)
            blurred = cv.bilateralFilter(board, d, colorSigma, spaceSigma)

        if scharrRate == 0:
            scharrXY = blurred.copy()
        else:
            scharrX = cv.Scharr(blurred, cv2.CV_64F, 1, 0)
            scharrY = cv.Scharr(blurred, cv2.CV_64F, 0, 1)
            scharrX = cv.convertScaleAbs(scharrX)
            scharrY = cv.convertScaleAbs(scharrY)
            scharrXY = cv.addWeighted(scharrX, scharrRate, scharrY, scharrRate, 0)
            scharrXY = cv.convertScaleAbs(scharrXY)
            scharrXY = cv.bitwise_and(scharrXY, upJointline)  # 将拼接处填充为黑色

        image_show("ScharrXY", scharrXY)
        img32 = np.float32(scharrXY)
        square1 = cv2.blur(np.multiply(img32, img32), (squareR, squareR))
        square2 = np.multiply(cv.blur(img32, (squareR, squareR)),
                              cv.blur(img32, (squareR, squareR)))
        squareDif32 = np.subtract(square1, square2)
        squareDif = squareDif32.copy()
        np.clip(squareDif32, 0, 255, out=squareDif)
        squareDif = squareDif.astype(np.uint8)
        image_show("SquareDif", squareDif)

        # 进行闭操作,让边界更加的凸显,就是放大白色背景轮廓,使得黑色区域闭合
        contourImg = squareDif.copy()
        kernelUsed = cv.getStructuringElement(cv.MORPH_RECT, (dilateKernel, dilateKernel))
        squareDifClosed = cv.morphologyEx(contourImg, cv2.MORPH_CLOSE,
                                          kernelUsed, iterations=closeTimes)
        image_show("SquareDifClosed", squareDifClosed)

        for index, thresOffset in enumerate(thresOffsetList):
            cv.destroyAllWindows()
            image_show(f"SquareDifClose_({thresOffset})", squareDifClosed)
            # 根据阈值进行分隔
            thresUsed = thresOffset
            print(f"第 {index + 1} 个阈值,使用的分割阈值为: {thresUsed}")
            _, contourImage = cv.threshold(squareDifClosed.copy(), thresUsed,
                                           255, cv.THRESH_BINARY)
            if scharrRate == 0:
                contourImage = cv.subtract(contourImage, cv2.bitwise_not(upJointline))
            # 如果图像拼接处,不是通过scharrXY获取的梯度图像,这里是为什么,我需要再看一下
            image_show(f"Threshold_({thresUsed})", contourImage)
            # 进行泛洪填充
            h, w = contourImage.shape[:2]
            mask = np.zeros((h + 2, w + 2), dtype=np.uint8)
            if contourImage[h // 2, w // 2] > 150:
                cv.floodFill(contourImage, mask, (h // 2, w // 2), 150)
            else:
                cv.floodFill(contourImage, mask, (h // 3, w // 3), 150)
            floodFill = np.zeros(contourImage.shape, dtype=np.uint8)
            floodFill[contourImage == 150] = 255
            image_show("FloodFill", floodFill)
            # 进行开操作,去除掉边界的噪点
            floodFill = cv.morphologyEx(floodFill, cv.MORPH_OPEN, kernelUsed, iterations=openTimes)
            image_show("FloodFillOpened", floodFill)
            res = check_inner_board_3p(floodFill, width, height, calcThresBig, calcThresSmall,
                                       boardColor, boardPos, upBox, downBox, totalBoard)
            print(f"计算结果: {res['result']},{res['info']},识别尺寸:{res['calcSize']},"
                  f"{(int(res['calcSize'][0] * cp.mm2pix), int(res['calcSize'][1] * cp.mm2pix))},"
                  f"误差:{res['calcError']}")
            if res["result"] == "ok":
                sizeOkRes.append(res)
                calcSize = res["calcSize"]
                calcError = res["calcError"]
                if get_sum_abs(calcError) < 7 and not isSizeCheck:
                    print(f"结果已找到,算法结束,使用的算子编号:{tryTimes},亮度阈值:{thresUsed},"
                          f"识别尺寸:{calcSize},误差:{calcError}")
                    return "ok", res["info"], res["box"]
                continue
            elif res["result"] != "error":
                if isSizeCheck:
                    sizeOkRes.append(res)
                else:
                    sizeDifRes.append(res)

    else:
        # 最外层循环结束之后
        if isSizeCheck:
            sizeList = []
            boxList = []
            if len(sizeOkRes) >= 1:
                resOkSorted = sorted(sizeOkRes, key=lambda x: get_sum_abs(x["calcError"]))
                for res in resOkSorted:
                    sizeList.append(res["calcSize"])
                    boxList.append(res["box"])
                return "ok", sizeList, boxList
            else:
                return "error", "内板寻找失败", None
        else:
            if len(sizeOkRes) >= 1:
                resOkSorted = sorted(sizeOkRes, key=lambda x: get_sum_abs(x["calcError"]))
                res = resOkSorted[0]
                print(f"返回的OK结果是,尺寸:{res['calcSize'],},"
                      f"{(int(res['calcSize'][0] * cp.mm2pix), int(res['calcSize'][1] * cp.mm2pix))},"
                      f"误差:{res['calcError']}")
                return "ok", res["info"], res["box"]
            elif len(sizeDifRes) >= 1:
                resDifSorted = sorted(sizeDifRes, key=lambda x: get_sum_abs(x["calcError"]))
                res = resDifSorted[0]
                return "sizeDif", res["info"], res["box"]
            else:
                return "error", "找内板失败", None


def get_size_check_result_3p(image, width, height, calcThresBig, totalBoardBox, totalBoard):
    """
    3拼板获取尺寸确认的结果
    @param image:
    @param width:
    @param height:
    @param calcThresBig:
    @param totalBoardBox:
    @param totalBoard:
    @return:
    """
    if image is None:
        return "error", None, None, None, None

    jointLineMask = np.ones(image.shape, dtype=np.uint8) * 255
    jointLineMask[cp.middleJointPos - jointLineExtend:cp.middleJointPos + jointLineExtend, :] = 0
    jointLineMask[cp.middleJointPos2 - jointLineExtend:cp.middleJointPos2 + jointLineExtend, :] = 0
    jointLineMaskNoAngle1, _ = get_board_without_angle(jointLineMask, totalBoardBox)

    cv.destroyAllWindows()
    image_show("TotalBoard", totalBoard)
    _, h = totalBoardBox[1]
    upBoard = totalBoard.copy()[:int(h * upBoxSlice), :]
    upJointline = jointLineMaskNoAngle1.copy()[:int(h * upBoxSlice), :]
    upRes, upSizes, upBoxes = get_inner_board_info_3p(upBoard, upJointline, width, height,
                                                      calcThresBig, calcThresBig, "up",
                                                      isFirstBoard=isFirstBoard, isSizeCheck=True,
                                                      upBox=None, downBox=None, totalBoard=totalBoard)
    upBoardResList = []
    upSizeResList = []
    upboardColor = cv.cvtColor(upBoard, cv.COLOR_GRAY2BGR)
    if upRes != "error":
        for index, upbox in enumerate(upBoxes):
            if upbox is not None:
                upBoardRes = upboardColor.copy()
                upBoardRes = cv.drawContours(upBoardRes, [np.array(upbox)],
                                             -1, colorGreen, 3)
                centerX, centerY = upBoard.shape[1] // 2, upBoard.shape[0] // 2

                cv.putText(upBoardRes, f"{index + 1}", (centerX - 8, centerY),
                           cv2.FONT_HERSHEY_SIMPLEX, 10, colorBlue, 5)
                image_show(f"upBoardRes_{index + 1}", upBoardRes)
                upBoardResList.append(upBoardRes)
                upSizeResList.append(upSizes[index])
        return "ok", upSizeResList, upBoardResList, upboardColor
    else:
        return "error", "内板识别出错", None, upboardColor


def get_boxes_3pin(image, width, height, calcThresBig, calcThresSmall, totalBoardBox,
                   totalBoard, isFirstBoard):
    """
    3拼板获取内板的逻辑
    @param image:
    @param width:
    @param height:
    @param calcThresBig:
    @param calcThresSmall:
    @param totalBoardBox:
    @param totalBoard:
    @param isFirstBoard:
    @return:
    """
    print(f"in get_boxes_3pin() isFirstBoard: {isFirstBoard}")
    w, h = totalBoardBox[1]
    totalBoardColor = cv.cvtColor(totalBoard, cv.COLOR_GRAY2BGR)
    jointLineMask = np.ones(image.shape, dtype=np.uint8) * 255
    # 横向进板的时候
    jointLineMask[cp.middleJointPos - jointLineExtend:cp.middleJointPos + jointLineExtend, :] = 0
    jointLineMask[cp.middleJointPos2 - jointLineExtend:cp.middleJointPos2 + jointLineExtend] = 0
    jointLineMaskNoAngle, _ = get_board_without_angle(jointLineMask, totalBoardBox)
    cv.destroyAllWindows()
    image_show("TotalBoard", totalBoard)
    upBoard = totalBoard.copy()[:int(h * upBoxSlice), :]
    middleBoard = totalBoard.copy()[int(h * middleBoxSlice[0]):int(h * middleBoxSlice[1]), :]
    downBoard = totalBoard.copy()[int(h * downBoxSlice):, :]
    upJointLine = jointLineMaskNoAngle[:int(h * upBoxSlice), :]
    middleJointLine = jointLineMaskNoAngle[int(h * middleBoxSlice[0]):int(h * middleBoxSlice[1]), :]
    downJointLine = jointLineMaskNoAngle[int(h * downBoxSlice):, :]
    boxesRes = []
    upRes, upInfo, upBox = get_inner_board_info_3p(upBoard, upJointLine, width, height,
                                                   calcThresBig, calcThresSmall, "up", isFirstBoard,
                                                   isSizeCheck=False, upBox=None, downBox=None,
                                                   totalBoard=totalBoard)
    if upRes != "ok":
        return False, upInfo, boxesRes

    downRes, downInfo, downBox = get_inner_board_info_3p(downBoard, downJointLine, width,
                                                         height, calcThresBig, calcThresSmall, "down",
                                                         isFirstBoard, isSizeCheck=False, upBox=upBox, downBox=None,
                                                         totalBoard=totalBoard)
    if downRes != "ok":
        return False, downInfo, boxesRes
    else:
        downBox = [(p[0], p[1] + int(h * downBoxSlice)) for p in downBox]

    middleRes, middleInfo, middleBox = get_inner_board_info_3p(middleBoard, middleJointLine,
                                                               width, height, calcThresBig, calcThresSmall, "middle",
                                                               isFirstBoard, False, upBox, downBox, totalBoard)
    if middleRes != "ok":
        return False, middleInfo, boxesRes
    else:
        middleBox = [(p[0], p[1] + int(h * middleBoxSlice[0])) for p in middleBox]

    cv2.drawContours(totalBoardColor,
                     [np.array(upBox), np.array(middleBox), np.array(downBox)],
                     -1, colorGreen, 3)
    image_show("ThreeBoxesFinded", totalBoardColor)
    boxesRes = [upBox, middleBox, downBox]
    return True, "识别成功!", boxesRes


def get_lines_with_boxes_3pin(image, totalBoard, totalBoardBox, totalBoardThres, boxesRes,
                              transMtx, topRemain, leftRemain, bottomRemain, rightRemain, totalBoardOffset):
    """
    根据识别出来的内框,获取切线,3拼板
    :param image:
    :param totalBoard:
    :param totalBoardBox:
    :param totalBoardThres:
    :param boxesRes:
    :param transMtx:
    :param topRemain:
    :param leftRemain:
    :param bottomRemain:
    :param rightRemain:
    :param totalBoardOffset:
    :return:
    """
    if len(image.shape) >= 3:
        image = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    imageColor = cv.cvtColor(image, cv.COLOR_GRAY2BGR)
    (cx, cy), (w, h), totalBoardAngle = totalBoardBox
    upBox, middleBox, downBox = boxesRes

    upLeftTop, upRightTop, upRightBottom, upLeftBottom = upBox
    middleLeftTop, middleRightTop, middleRightBottom, middleLeftBottom = middleBox
    downLeftTop, downRightTop, downRightBottom, downLeftBottom = downBox

    leftCutLineK = get_linear_fit_k_vertical(np.array([upLeftTop, upLeftBottom,
                                                       middleLeftTop, middleLeftBottom,
                                                       downLeftTop, downLeftBottom]))
    if leftCutLineK is None:
        leftCutLineB = min(upLeftTop[0], upLeftBottom[0], middleLeftTop[0],
                           middleLeftBottom[0], downLeftTop[0], downLeftBottom[0]) - leftRemain
    else:
        upLeftTopX = upLeftTop[1] - (upLeftTop[0] - leftRemain) * leftCutLineK
        upLeftBottomX = upLeftBottom[1] - (upLeftBottom[0] - leftRemain) * leftCutLineK
        middleLeftTopX = middleLeftTop[1] - (middleLeftTop[0] - leftRemain) * leftCutLineK
        middleLeftBottomX = (middleLeftBottom[1] - (middleLeftBottom[0] - leftRemain) *
                             leftCutLineK)
        downLeftTopX = downLeftTop[1] - (downLeftTop[0] - leftRemain) * leftCutLineK
        downLeftBottomX = downLeftBottom[1] - (downLeftBottom[0] - leftRemain) * leftCutLineK

        if leftCutLineK > 0:  # 当k大于0的时候,b越大,越靠左
            leftCutLineB = max(upLeftTopX, upLeftBottomX, middleLeftTopX, middleLeftBottomX,
                               downLeftTopX, downLeftBottomX)
        else:
            leftCutLineB = min(upLeftTopX, upLeftBottomX, middleLeftTopX, middleLeftBottomX,
                               downLeftTopX, downLeftBottomX)

    rightCutLineK = get_linear_fit_k_vertical(np.array([upRightTop, upRightBottom,
                                                        middleRightTop,
                                                        middleRightBottom, downRightTop, downRightBottom]))
    if rightCutLineK is None:
        rightCutLineB = max(upRightTop[0], upRightBottom[0], middleRightTop[0],
                            middleRightBottom[0], downRightTop[0], downRightBottom[0]) + rightRemain
    else:
        upRightTopX = upRightTop[1] - (upRightTop[0] + rightRemain) * rightCutLineK
        upRightBottomX = upRightBottom[1] - (upRightBottom[0] + rightRemain) * rightCutLineK
        middleRightTopX = middleRightTop[1] - (middleRightTop[0] + rightRemain) * rightCutLineK
        middleRightBottomX = (middleRightBottom[1] - (middleRightBottom[0] + rightRemain) *
                              rightCutLineK)
        downRightTopX = downRightTop[1] - (downRightTop[0] + rightRemain) * rightCutLineK
        downRightBottomX = (downRightBottom[1] - (downRightBottom[0] + rightRemain) *
                            rightCutLineK)
        if rightCutLineK > 0:  # 当k大于0的时候,b越大,越靠左
            rightCutLineB = min(upRightTopX, upRightBottomX, middleRightTopX,
                                middleRightBottomX, downRightTopX, downRightBottomX)
        else:
            rightCutLineB = max(upRightTopX, upRightBottomX, middleRightTopX,
                                middleRightBottomX, downRightTopX, downRightBottomX)

    topCutLineK = get_line_k_and_b(upLeftTop, upRightTop)[0]
    if topCutLineK is None:
        cv.destroyAllWindows()
        return False, None, None
    else:
        topCutLineB = topCutLineK * -1 * (upLeftTop[0]) + (upLeftTop[1] - topRemain)

    bottomCutLineK = get_line_k_and_b(downLeftBottom, downRightBottom)[0]
    if bottomCutLineK is None:
        # 垂直，一定是异常
        cv.destroyAllWindows()
        return False, None, None, None
    else:
        bottomCutLineB = bottomCutLineK * -1 * (downLeftBottom[0]) + downLeftBottom[1] + bottomRemain

    # 先分别求出来两个中缝的角度,firstMiddleK,secondMiddleK,然后两个中缝求一个角平分线,按照这个角平分线搞中缝的角度
    firstMiddleK, firstMiddleB = get_middle_cut_line(upLeftBottom, upRightBottom, middleLeftTop, middleRightTop)
    secondMiddleK, secondMiddleB = get_middle_cut_line(middleLeftBottom, middleRightBottom, downLeftTop, downRightTop)
    # 求中点,两个中点y值,一个是上框和中框的中点的中点,一个是中框和下框的中点的y值
    firstMiddleY = (get_two_points_middle(upLeftBottom, upRightBottom)[1] +
                    get_two_points_middle(middleLeftTop, middleRightTop)[1]) / 2
    secondMiddleY = (get_two_points_middle(middleLeftBottom, middleRightBottom)[1] +
                     get_two_points_middle(downLeftTop, downRightTop)[1]) / 2
    firstMiddleLine, secondMiddleLine = get_two_lines_angular_bisector(firstMiddleK, firstMiddleB, secondMiddleK,
                                                                       secondMiddleB, firstMiddleY, secondMiddleY)
    firstMiddleK, firstMiddleB = firstMiddleLine
    secondMiddleK, secondMiddleB = secondMiddleLine

    boardLeftTop = [0, 0]
    boardRightTop = [w, 0]
    boardLeftBottom = [0, h]
    boardRightBottom = [w, h]
    findEdgeExtend = int(7 * cp.mm2pix)  # 找边缘的时候延长10个mm
    totalBoardExtendForFindEdge, _ = get_board_without_angle(image, totalBoardBox, findEdgeExtend)
    totalBoardThresForFindEdge, _ = get_board_without_angle(totalBoardThres, totalBoardBox, findEdgeExtend)

    leftTopY = upLeftTop[1] - topRemain
    rightTopY = upRightTop[1] - topRemain
    if leftTopY < 0 or rightTopY < 0:
        topRemain = 0
    leftBottomY = downLeftBottom[1] + bottomRemain
    rightBottomY = downRightBottom[1] + bottomRemain
    if leftBottomY > totalBoard.shape[0] or rightBottomY > totalBoard.shape[0]:
        bottomRemain = 0

    if topRemain == 0:
        topLineK, topLineB = find_first_edge_line(totalBoardExtendForFindEdge, totalBoardThresForFindEdge, findEdgeExtend, upLeftTop, upRightTop)
        if topLineK is not None:
            topCutLineK, topCutLineB = topLineK, topLineB
        else:
            topCutLineK, topCutLineB = get_line_k_and_b(boardLeftTop, boardRightTop)

    if bottomRemain == 0:
        bottomLineK, bottomLineB = find_third_edge_line(totalBoardExtendForFindEdge, totalBoardThresForFindEdge, findEdgeExtend)
        if bottomLineK is not None:
            bottomCutLineK, bottomCutLineB = bottomLineK, bottomLineB
        else:
            bottomCutLineK, bottomCutLineB = get_line_k_and_b(boardLeftBottom, boardRightBottom)
    if leftRemain == 0:
        leftCutLineK, leftCutLineB = get_line_k_and_b(boardLeftBottom, boardLeftTop)
    if rightRemain == 0:
        rightCutLineK, rightCutLineB = get_line_k_and_b(boardRightTop, boardRightBottom)

    # 求所有线的交点
    leftTopCross = get_two_lines_intersection(topCutLineK, topCutLineB, leftCutLineK, leftCutLineB)
    rightTopCross = get_two_lines_intersection(topCutLineK, topCutLineB, rightCutLineK, rightCutLineB)
    leftFirstMiddleCross = get_two_lines_intersection(firstMiddleK, firstMiddleB, leftCutLineK, leftCutLineB)
    rightFirstMiddleCross = get_two_lines_intersection(firstMiddleK, firstMiddleB, rightCutLineK, rightCutLineB)
    leftSecondMiddleCross = get_two_lines_intersection(secondMiddleK, secondMiddleB, leftCutLineK, leftCutLineB)
    rightSecondMiddleCross = get_two_lines_intersection(secondMiddleK, secondMiddleB, rightCutLineK, rightCutLineB)
    leftBottomCross = get_two_lines_intersection(bottomCutLineK, bottomCutLineB, leftCutLineK, leftCutLineB)
    rightBottomCross = get_two_lines_intersection(bottomCutLineK, bottomCutLineB, rightCutLineK, rightCutLineB)

    extend = int(8 * cp.mm2pix)
    extendLeftRight = int(20 * cp.mm2pix)

    topCutLeftPoint = [- extend, topCutLineK * (- extend) + topCutLineB]
    topCutRightPoint = [extend + w, topCutLineK * (extend + w) + topCutLineB]

    bottomCutRightPoint = [w + extend, bottomCutLineK * (w + extend) + bottomCutLineB]
    bottomCutLeftPoint = [- extend, bottomCutLineK * (- extend) + bottomCutLineB]

    if leftCutLineK is None:
        # 按照整个物料的高度去延长切线
        # leftCutLineBottom = [leftCutLineB, h + extendLeftRight]
        # leftCutLineTop = [leftCutLineB, -extendLeftRight]
        # 按照交点延长去切
        leftCutLineBottom = [leftCutLineB, leftBottomCross[1] + extendLeftRight]
        leftCutLineTop = [leftCutLineB, leftTopCross[1] - extendLeftRight]
    elif leftCutLineK != 0:
        # 按照整个物料的高度去延长切线
        # leftCutLineBottom = [((h + extendLeftRight) - leftCutLineB) / leftCutLineK, h + extendLeftRight]
        # leftCutLineTop = [(- extendLeftRight - leftCutLineB) / leftCutLineK, - extendLeftRight]
        # 按照和1,3刀的交点延长切线
        leftCutLineBottom = [((leftBottomCross[1] + extendLeftRight) - leftCutLineB) / leftCutLineK,
                             leftBottomCross[1] + extendLeftRight]
        leftCutLineTop = [(leftTopCross[1] - extendLeftRight - leftCutLineB) / leftCutLineK,
                          leftTopCross[1] - extendLeftRight]
    else:
        cv.destroyAllWindows()
        return False, None, None, None

    if rightCutLineK is None:
        # 按照整个物料的高度去延长切线
        # rightCutLineTop = [rightCutLineB, - extendLeftRight]
        # rightCutLineBottom = [rightCutLineB, h + extendLeftRight]
        # 按照和13刀的交点去延长切线
        rightCutLineTop = [rightCutLineB, rightTopCross[1] - extendLeftRight]
        rightCutLineBottom = [rightCutLineB, rightBottomCross[1] + extendLeftRight]
    elif rightCutLineK != 0:
        # 按照整个物料的高度去延长切线
        # rightCutLineTop = [((- extendLeftRight) - rightCutLineB) / rightCutLineK,
        #                    - extendLeftRight]
        # rightCutLineBottom = [((h + extendLeftRight) - rightCutLineB) / rightCutLineK,
        #                       h + extendLeftRight]
        # 按照和13刀的交点去延长切线
        rightCutLineTop = [((rightTopCross[1] - extendLeftRight) - rightCutLineB) / rightCutLineK,
                           rightTopCross[1] - extendLeftRight]
        rightCutLineBottom = [((rightBottomCross[1] + extendLeftRight) - rightCutLineB) / rightCutLineK,
                              rightBottomCross[1] + extendLeftRight]
    else:
        cv.destroyAllWindows()
        return False, None, None, None
    rotatedCenter = (cx, cy)
    M = cv.getRotationMatrix2D(rotatedCenter, -totalBoardAngle, 1)
    centerOffset = totalBoardOffset

    boardLeftTopBig = np.dot(M, [boardLeftTop[0] + centerOffset[0], boardLeftTop[1] + centerOffset[1], 1])
    boardRightTopBig = np.dot(M, [boardRightTop[0] + centerOffset[0], boardRightTop[1] + centerOffset[1], 1])
    boardRightBottomBig = np.dot(M, [boardRightBottom[0] + centerOffset[0], boardRightBottom[1] + centerOffset[1], 1])
    boardLeftBottomBig = np.dot(M, [boardLeftBottom[0] + centerOffset[0], boardLeftBottom[1] + centerOffset[1], 1])

    topCutLeftPointBig = np.dot(M, [topCutLeftPoint[0] + centerOffset[0], topCutLeftPoint[1] + centerOffset[1], 1])
    topCutRightPointBig = np.dot(M, [topCutRightPoint[0] + centerOffset[0], topCutRightPoint[1] + centerOffset[1], 1])
    bottomCutRightPointBig = np.dot(M, [bottomCutRightPoint[0] + centerOffset[0], bottomCutRightPoint[1] + centerOffset[1], 1])
    bottomCutLeftPointBig = np.dot(M, [bottomCutLeftPoint[0] + centerOffset[0], bottomCutLeftPoint[1] + centerOffset[1], 1])
    leftCutLineBottomBig = np.dot(M, [leftCutLineBottom[0] + centerOffset[0], leftCutLineBottom[1] + centerOffset[1], 1])
    leftCutLineTopBig = np.dot(M, [leftCutLineTop[0] + centerOffset[0], leftCutLineTop[1] + centerOffset[1], 1])
    rightCutLineTopBig = np.dot(M, [rightCutLineTop[0] + centerOffset[0], rightCutLineTop[1] + centerOffset[1], 1])
    rightCutLineBottomBig = np.dot(M, [rightCutLineBottom[0] + centerOffset[0], rightCutLineBottom[1] + centerOffset[1], 1])

    firstMiddleCutLineLeftBig = np.dot(M, [leftFirstMiddleCross[0] + centerOffset[0],
                                           leftFirstMiddleCross[1] + centerOffset[1], 1])
    firstMiddleCutLineRightBig = np.dot(M, [rightFirstMiddleCross[0] + centerOffset[0],
                                            rightFirstMiddleCross[1] + centerOffset[1], 1])
    secondMiddleCutLineLeftBig = np.dot(M, [leftSecondMiddleCross[0] + centerOffset[0],
                                            leftSecondMiddleCross[1] + centerOffset[1], 1])
    secondMiddleCutLineRightBig = np.dot(M, [rightSecondMiddleCross[0] + centerOffset[0],
                                             rightSecondMiddleCross[1] + centerOffset[1], 1])

    # 重新将端点定位到大图上去
    upLeftBottom = np.dot(M, [upLeftBottom[0] + centerOffset[0], upLeftBottom[1] + centerOffset[1], 1])
    upRightBottom = np.dot(M, [upRightBottom[0] + centerOffset[0], upRightBottom[1] + centerOffset[1], 1])
    upLeftTop = np.dot(M, [upLeftTop[0] + centerOffset[0], upLeftTop[1] + centerOffset[1], 1])
    upRightTop = np.dot(M, [upRightTop[0] + centerOffset[0], upRightTop[1] + centerOffset[1], 1])

    middleLeftBottom = np.dot(M, [middleLeftBottom[0] + centerOffset[0], middleLeftBottom[1] + centerOffset[1], 1])
    middleRightBottom = np.dot(M, [middleRightBottom[0] + centerOffset[0], middleRightBottom[1] + centerOffset[1], 1])
    middleLeftTop = np.dot(M, [middleLeftTop[0] + centerOffset[0], middleLeftTop[1] + centerOffset[1], 1])
    middleRightTop = np.dot(M, [middleRightTop[0] + centerOffset[0], middleRightTop[1] + centerOffset[1], 1])

    downLeftTop = np.dot(M, [downLeftTop[0] + centerOffset[0], downLeftTop[1] + centerOffset[1], 1])
    downLeftBottom = np.dot(M, [downLeftBottom[0] + centerOffset[0], downLeftBottom[1] + centerOffset[1], 1])
    downRightTop = np.dot(M, [downRightTop[0] + centerOffset[0], downRightTop[1] + centerOffset[1], 1])
    downRightBottom = np.dot(M, [downRightBottom[0] + centerOffset[0], downRightBottom[1] + centerOffset[1], 1])

    # 画出内框
    cv.line(imageColor, (int(upLeftBottom[0]), int(upLeftBottom[1])), (int(upRightBottom[0]), int(upRightBottom[1])),
            colorGreen, 3)
    cv.line(imageColor, (int(upLeftBottom[0]), int(upLeftBottom[1])), (int(upLeftTop[0]), int(upLeftTop[1])), colorGreen,
            3)
    cv.line(imageColor, (int(upRightBottom[0]), int(upRightBottom[1])), (int(upRightTop[0]), int(upRightTop[1])),
            colorGreen, 3)
    cv.line(imageColor, (int(upLeftTop[0]), int(upLeftTop[1])), (int(upRightTop[0]), int(upRightTop[1])), colorGreen, 3)

    cv.line(imageColor, (int(downLeftBottom[0]), int(downLeftBottom[1])),
            (int(downRightBottom[0]), int(downRightBottom[1])), colorGreen, 3)
    cv.line(imageColor, (int(downLeftBottom[0]), int(downLeftBottom[1])), (int(downLeftTop[0]), int(downLeftTop[1])),
            colorGreen, 3)
    cv.line(imageColor, (int(downRightBottom[0]), int(downRightBottom[1])), (int(downRightTop[0]), int(downRightTop[1])),
            colorGreen, 3)
    cv.line(imageColor, (int(downLeftTop[0]), int(downLeftTop[1])), (int(downRightTop[0]), int(downRightTop[1])),
            colorGreen, 3)

    cv.line(imageColor, (int(middleLeftBottom[0]), int(middleLeftBottom[1])),
            (int(middleRightBottom[0]), int(middleRightBottom[1])), colorGreen, 3)
    cv.line(imageColor, (int(middleLeftBottom[0]), int(middleLeftBottom[1])), (int(middleLeftTop[0]), int(middleLeftTop[1])),
            colorGreen, 3)
    cv.line(imageColor, (int(middleRightBottom[0]), int(middleRightBottom[1])), (int(middleRightTop[0]), int(middleRightTop[1])),
            colorGreen, 3)
    cv.line(imageColor, (int(middleLeftTop[0]), int(middleLeftTop[1])), (int(middleRightTop[0]), int(middleRightTop[1])),
            colorGreen, 3)

    # 画出上，下，左，右，中五条切线
    textScale = 3
    textThickness = 8
    cv.line(imageColor, (int(topCutLeftPointBig[0]), int(topCutLeftPointBig[1])),
            (int(topCutRightPointBig[0]), int(topCutRightPointBig[1])), colorRed, 3)
    cv.putText(imageColor, '1', (int((topCutLeftPointBig[0] + topCutRightPointBig[0]) / 2),
                                 int((topCutLeftPointBig[1] + topCutRightPointBig[1]) / 2) - 40),
               cv.FONT_HERSHEY_COMPLEX, textScale, colorRed, textThickness)
    cv.line(imageColor, (int(bottomCutRightPointBig[0]), int(bottomCutRightPointBig[1])),
            (int(bottomCutLeftPointBig[0]), int(bottomCutLeftPointBig[1])), colorRed, 3)
    cv.putText(imageColor, '3', (int((bottomCutRightPointBig[0] + bottomCutLeftPointBig[0]) / 2),
                                 int((bottomCutRightPointBig[1] + bottomCutLeftPointBig[1]) / 2) + 90),
               cv.FONT_HERSHEY_COMPLEX, textScale, colorRed, textThickness)

    cv.line(imageColor, (int(leftCutLineBottomBig[0]), int(leftCutLineBottomBig[1])),
            (int(leftCutLineTopBig[0]), int(leftCutLineTopBig[1])), colorRed, 3)
    cv.putText(imageColor, '2', (int((leftCutLineBottomBig[0] + leftCutLineTopBig[0]) / 2) - 100,
                                 int((leftCutLineBottomBig[1] + leftCutLineTopBig[1]) / 2)),
               cv.FONT_HERSHEY_COMPLEX, textScale, colorRed, textThickness)
    cv.line(imageColor, (int(rightCutLineTopBig[0]), int(rightCutLineTopBig[1])),
            (int(rightCutLineBottomBig[0]), int(rightCutLineBottomBig[1])), colorRed, 3)
    cv.putText(imageColor, '4', (int((rightCutLineTopBig[0] + rightCutLineBottomBig[0]) / 2) + 30,
                                 int((rightCutLineTopBig[1] + rightCutLineBottomBig[1]) / 2)),
               cv.FONT_HERSHEY_COMPLEX, textScale, colorRed, textThickness)
    cv.line(imageColor, (int(firstMiddleCutLineLeftBig[0]), int(firstMiddleCutLineLeftBig[1])),
            (int(firstMiddleCutLineRightBig[0]), int(firstMiddleCutLineRightBig[1])), colorBlue, 3)
    cv.line(imageColor, (int(secondMiddleCutLineLeftBig[0]), int(secondMiddleCutLineLeftBig[1])),
            (int(secondMiddleCutLineRightBig[0]), int(secondMiddleCutLineRightBig[1])), colorBlue, 3)

    # 将所有的点都转换为机械手上的坐标
    topCutLeftPointRobot = pix_pos_to_robot(topCutLeftPointBig, transMtx)
    topCutRightPointRobot = pix_pos_to_robot(topCutRightPointBig, transMtx)
    bottomCutLeftPointRobot = pix_pos_to_robot(bottomCutLeftPointBig, transMtx)
    bottomCutRightPointRobot = pix_pos_to_robot(bottomCutRightPointBig, transMtx)
    leftCutLineBottomRobot = pix_pos_to_robot(leftCutLineBottomBig, transMtx)
    leftCutLineTopRobot = pix_pos_to_robot(leftCutLineTopBig, transMtx)
    rightCutLineTopRobot = pix_pos_to_robot(rightCutLineTopBig, transMtx)
    rightCutLineBottomRobot = pix_pos_to_robot(rightCutLineBottomBig, transMtx)
    firstMiddleCutLineLeftRobot = pix_pos_to_robot(firstMiddleCutLineLeftBig, transMtx)
    firstMiddleCutLineRightRobot = pix_pos_to_robot(firstMiddleCutLineRightBig, transMtx)
    secondMiddleCutLineLeftRobot = pix_pos_to_robot(secondMiddleCutLineLeftBig, transMtx)
    secondMiddleCutLineRightRobot = pix_pos_to_robot(secondMiddleCutLineRightBig, transMtx)

    boardLeftTopRobot = pix_pos_to_robot(boardLeftTopBig, transMtx)
    boardRightTopRobot = pix_pos_to_robot(boardRightTopBig, transMtx)
    boardRightBottomRobot = pix_pos_to_robot(boardRightBottomBig, transMtx)
    boardLeftBottomRobot = pix_pos_to_robot(boardLeftBottomBig, transMtx)

    cutDisTotal = 0
    cutAreaTotal = 0
    if topRemain != 0:
        cutDis = get_two_point_distance(topCutLeftPointRobot, topCutRightPointRobot)
        area = cutDis * (get_two_point_distance(get_two_points_middle(topCutLeftPointRobot, topCutRightPointRobot),
                                                get_two_points_middle(boardLeftTopRobot, boardRightTopRobot)))
        cutAreaTotal += area
        cutDisTotal += cutDis
    if leftRemain != 0:
        cutDis = get_two_point_distance(leftCutLineBottomRobot, leftCutLineTopRobot)
        area = cutDis * (get_two_point_distance(get_two_points_middle(leftCutLineBottomRobot, leftCutLineTopRobot),
                                                get_two_points_middle(boardLeftTopRobot, boardLeftBottomRobot)))
        cutAreaTotal += area
        cutDisTotal += cutDis

    if bottomRemain != 0:
        cutDis = get_two_point_distance(bottomCutRightPointRobot, bottomCutLeftPointRobot)
        area = cutDis * (get_two_point_distance(get_two_points_middle(bottomCutRightPointRobot, bottomCutLeftPointRobot),
                                                get_two_points_middle(boardLeftBottomRobot, boardRightBottomRobot)))
        cutAreaTotal += area
        cutDisTotal += cutDis

    if rightRemain != 0:
        cutDis = get_two_point_distance(rightCutLineTopRobot, rightCutLineBottomRobot)
        area = cutDis * (get_two_point_distance(get_two_points_middle(rightCutLineTopRobot, rightCutLineBottomRobot),
                                                get_two_points_middle(boardRightTopRobot, boardRightBottomRobot)))
        cutAreaTotal += area
        cutDisTotal += cutDis

    imageResult, _ = get_board_without_angle(imageColor, totalBoardBox, extend=80)
    image_show("resultImage", imageResult)
    # 以裁切机的实际切线为标准，计算前板长，后板长，总长
    # 先算中线中点
    firstLength, secondLength, thirdLength = get_board_length_three([topCutLeftPointRobot, topCutRightPointRobot],
                                                                    [firstMiddleCutLineLeftRobot, firstMiddleCutLineRightRobot],
                                                                    [secondMiddleCutLineLeftRobot, secondMiddleCutLineRightRobot],
                                                                    [bottomCutLeftPointRobot, bottomCutRightPointRobot])

    topFirstMiddleAngle = get_two_line_angle(firstMiddleCutLineRightRobot, firstMiddleCutLineLeftRobot,
                                             topCutRightPointRobot, topCutLeftPointRobot)
    bottomFirstMiddleAngle = get_two_line_angle(firstMiddleCutLineRightRobot, firstMiddleCutLineLeftRobot,
                                                bottomCutRightPointRobot, bottomCutLeftPointRobot)
    twoMiddleAngle = get_two_line_angle(secondMiddleCutLineRightRobot, secondMiddleCutLineLeftRobot,
                                        firstMiddleCutLineRightRobot, firstMiddleCutLineLeftRobot)
    bottomSecondMiddleAngle = get_two_line_angle(secondMiddleCutLineRightRobot, secondMiddleCutLineLeftRobot,
                                                 bottomCutRightPointRobot, bottomCutLeftPointRobot)

    # 是否切第一刀
    isFirstCut = True if topRemain != 0 else False
    isThirdCut = True if bottomRemain != 0 else False
    cutLength = [round(cutDisTotal, 5), round(cutAreaTotal, 5)]
    angleList = [topFirstMiddleAngle, bottomFirstMiddleAngle, twoMiddleAngle, bottomSecondMiddleAngle]
    cutWidth = get_two_point_distance(leftCutLineTopRobot, rightCutLineTopRobot)
    print("length:{},{},{},angleList:{},{},{},{}".format(firstLength, secondLength, thirdLength,
                                                         angleList[0], angleList[1], angleList[2], angleList[3]))

    return [topCutLeftPointRobot, topCutRightPointRobot, bottomCutRightPointRobot, bottomCutLeftPointRobot,
            leftCutLineBottomRobot, leftCutLineTopRobot, rightCutLineTopRobot, rightCutLineBottomRobot,
            firstMiddleCutLineLeftRobot, firstMiddleCutLineRightRobot, secondMiddleCutLineLeftRobot, secondMiddleCutLineRightRobot,
            firstLength, secondLength, thirdLength, angleList], imageResult, cutLength, isFirstCut, isThirdCut, cutWidth


if __name__ == '__main__':
    isFirstBoard = False
    filePath = r"D:\2024\sanqiang\3pin"
    _, data = db.get_line_cam_check_thres()
    totalHeightMax = data.get("totalHeightMax")
    totalHeightMin = data.get("totalHeightMin")
    boardBreak = False
    calcThresBig = 20
    calcThresSmall = 10
    _, transMtxData = db.get_trans_mtx_data()
    mtx = transMtxData.get("mtxLeft", [[1, 0, 1], [0, 1, 0]])
    jointNumber = "3"
    remainEdgeMm = [0, 15, 0, 15]
    topRemain, leftRemain, bottomRemian, rightRemain = [int(cp.mm2pix * x) for x in remainEdgeMm]
    keepDir = filePath
    if not os.path.isdir(keepDir):
        keepDir, _ = os.path.split(keepDir)
    keepOkPath = os.path.join(keepDir, "ok")
    keepOkResPath = os.path.join(keepDir, "cutlines")
    keepFailPath = os.path.join(keepDir, "fail")
    keepFirstSizeBestRes = os.path.join(keepDir, "first_size_check_best")

    for dirUsed in [keepOkPath, keepOkResPath, keepFailPath, keepFirstSizeBestRes]:
        if not os.path.exists(dirUsed):
            os.makedirs(dirUsed)
    fileNames = []
    if os.path.isfile(filePath):
        fileDir, fileName = os.path.split(filePath)
        fileNames.append(fileName)
    else:
        fileDir = filePath
        for root, dirs, files in os.walk(filePath):
            if root != filePath:
                continue
            for file in files:
                if file[-4:] != ".bmp":
                    continue
                fileNames.append(file)

    for index, fileName in enumerate(fileNames):
        filePathReal = os.path.join(fileDir, fileName)
        srcW, srcH = get_width_height_by_image_name_2pin(fileName)
        if srcW is None or srcH is None:
            print("*" * 10 + f"第 {index + 1} 张图 ({fileName}),图像名称错误,已跳过!")
            continue
        print("*" * 10 + f"第 {index + 1} 张图 ({fileName}),开始识别.")
        calcStart = time.time()
        imageSrc = cv.imread(filePathReal, cv.IMREAD_GRAYSCALE)
        totalBoardRes = check_total_board_is_ok(imageSrc, totalHeightMax, totalHeightMin,
                                                boardBreak, jointNumber)
        (ret, hintInfo, totalBoardBox, totalBoardNoAngle, totalBoardOffset,
         totalBoardThresWithAngle, totalBoardResWithAngle) = totalBoardRes
        print(f"物料检测结果: {ret},{hintInfo}")

        if isFirstBoard:
            resFirst, boardSizeList, boardResList, upBoard = get_size_check_result_3p(imageSrc, srcW, srcH,
                                                                                      calcThresBig, totalBoardBox, totalBoardNoAngle)
            if resFirst != "error":
                sizeCheckResBest = boardResList[0]
                sizeCheckResBest = get_size_scale_image(sizeCheckResBest, sizeScale=4)
                cv.imwrite(os.path.join(keepFirstSizeBestRes, fileName), sizeCheckResBest)
        res, info, boxesRes = get_boxes_3pin(imageSrc, srcW, srcH, calcThresBig, calcThresSmall, totalBoardBox,
                                             totalBoardNoAngle, isFirstBoard)
        if res:
            lineRes = get_lines_with_boxes_3pin(imageSrc, totalBoardNoAngle, totalBoardBox,
                                                totalBoardThresWithAngle, boxesRes, mtx, topRemain, leftRemain,
                                                bottomRemian, rightRemain, totalBoardOffset)
            cutLines, imageRes, cutDis, isFirstCut, isThirdCut, cutWidth = lineRes
            os.remove(filePathReal)
            imageRes = get_size_scale_image(imageRes, sizeScale=4)
            cv.imwrite(os.path.join(keepOkResPath, fileName), imageRes)
            cv.imwrite(os.path.join(keepOkPath, fileName), imageSrc)
            print(f"识别成功,切割面积:{cutDis},切割宽度:{cutWidth},角度长度:{cutLines[-4:]}"
                  f"算法耗时:{time.time() - calcStart}")
            continue
        else:
            print(f"XXXXXXXXXXXXXX识别失败,算法耗时:{time.time() - calcStart}")
            cv.imwrite(os.path.join(keepFailPath, fileName), imageSrc)
            os.remove(filePathReal)
